# -*- coding: utf-8 -*-
# @Time : 2024/8/6 16:31
# @Author : sdk007

import os
import platform
import re
from ctypes import *
from enum import Enum

def system_get_platform_info():
    sys_platform = platform.system().lower().strip()
    python_bit = platform.architecture()[0]
    python_bit_num = re.findall('(\d+)\w*', python_bit)[0]
    return sys_platform, python_bit_num

sys_platform, python_bit_num = system_get_platform_info()
system_type = sys_platform + python_bit_num

if sys_platform == 'linux':
    load_library = cdll.LoadLibrary
    fun_ctype = CFUNCTYPE
elif sys_platform == 'windows':
    load_library = windll.LoadLibrary
    fun_ctype = WINFUNCTYPE
else:
    print("************不支持的平台**************")
    exit(0)

netsdkdllpath_dict = {'windows64': os.path.dirname(__file__) + '\\lib\\' + 'HCNetSDK.dll',
                      'windows32': os.path.dirname(__file__) + '\\lib\\' + 'HCNetSDK.dll',
                      'linux64': os.path.dirname(__file__) + '/lib/libhcnetsdk.so',
                      'linux32': os.path.dirname(__file__) + '/lib/libhcnetsdk.so'}
netsdkdllpath = netsdkdllpath_dict[system_type]

C_LLONG_DICT = {'windows64': c_longlong, 'windows32': c_long, 'linux32': c_long, 'linux64': c_long}
C_LONG_DICT = {'windows64': c_long, 'windows32': c_long, 'linux32': c_int, 'linux64': c_int}
C_LDWORD_DICT = {'windows64': c_longlong, 'windows32': c_ulong, 'linux32': c_long, 'linux64': c_long}
C_DWORD_DICT = {'windows64': c_uint, 'windows32': c_uint, 'linux32': c_uint, 'linux64': c_uint}
C_HWND_DICT = {'windows64': c_void_p, 'windows32': c_void_p, 'linux32': c_uint, 'linux64': c_uint}

C_LLONG = C_LLONG_DICT[system_type]
C_LONG = C_LONG_DICT[system_type]
C_LDWORD = C_LDWORD_DICT[system_type]
C_DWORD = C_DWORD_DICT[system_type]
# C_BOOL = c_int
# C_UINT = c_uint
# C_BYTE = c_ubyte
# C_ENUM = c_int

C_HWND = C_HWND_DICT[system_type]
C_WORD = c_ushort
C_USHORT = c_ushort
C_SHORT = c_short
# C_LONG = c_int
C_BYTE = c_ubyte
C_UINT = c_uint
C_LPVOID = c_void_p
C_HANDLE = c_void_p
C_LPDWORD = POINTER(c_uint)
C_UINT64 = c_ulonglong
C_INT64 = c_longlong
C_BOOL = c_int

# ========== 添加所有必要的常量定义 ==========
NET_DVR_GET_NETCFG = 102
NET_DVR_GET_NETCFG_V50 = 1015
NET_DVR_SET_NETCFG_V50 = 1016
NET_DVR_SYSHEAD = 1
NET_DVR_STREAMDATA = 2
NET_DVR_AUDIOSTREAMDATA = 3
NET_DVR_PRIVATE_DATA = 112
NET_DVR_PLAYSTART = 1
NET_DVR_PLAYSTOP = 2
NET_DVR_SETUPALARM = 1
NET_DVR_CLOSEALARM = 2

# ========== 添加枚举定义 ==========
class NET_SDK_LOCAL_CFG_TYPE(Enum):
    NET_SDK_LOCAL_CFG_TYPE_TCP_PORT_BIND = 0
    NET_SDK_LOCAL_CFG_TYPE_UDP_PORT_BIND = 1
    NET_SDK_LOCAL_CFG_TYPE_MEM_POOL = 2
    NET_SDK_LOCAL_CFG_TYPE_MODULE_RECV_TIMEOUT = 3
    NET_SDK_LOCAL_CFG_TYPE_ABILITY_PARSE = 4
    NET_SDK_LOCAL_CFG_TYPE_TALK_MODE = 5
    NET_SDK_LOCAL_CFG_TYPE_PROTECT_KEY = 6
    NET_SDK_LOCAL_CFG_TYPE_CFG_VERSION = 7
    NET_SDK_LOCAL_CFG_TYPE_RTSP_PARAMS = 8
    NET_SDK_LOCAL_CFG_TYPE_SIMXML_LOGIN = 9
    NET_SDK_LOCAL_CFG_TYPE_CHECK_DEV = 10
    NET_SDK_LOCAL_CFG_TYPE_SECURITY = 11
    NET_SDK_LOCAL_CFG_TYPE_EZVIZLIB_PATH = 12
    NET_SDK_LOCAL_CFG_TYPE_CHAR_ENCODE = 13
    NET_SDK_LOCAL_CFG_TYPE_PROXYS = 14
    NET_DVR_LOCAL_CFG_TYPE_LOG = 15
    NET_DVR_LOCAL_CFG_TYPE_STREAM_CALLBACK = 16
    NET_DVR_LOCAL_CFG_TYPE_GENERAL = 17
    NET_DVR_LOCAL_CFG_TYPE_PTZ = 17
    NET_DVR_LOCAL_CFG_MESSAGE_CALLBACK_V51 = 19
    NET_SDK_LOCAL_CFG_CERTIFICATION = 20
    NET_SDK_LOCAL_CFG_PORT_MULTIPLEX = 21
    NET_SDK_LOCAL_CFG_ASYNC = 22
    NET_SDK_P2P_LOGIN_2C = 23
    NET_SDK_P2P_LOGIN_2B = 24
    NET_SDK_P2P_LOGOUT = 25
    NET_SDK_AUDIOCAST_CFG = 26

class NET_SDK_INIT_CFG_TYPE(Enum):
    NET_SDK_INIT_CFG_TYPE_CHECK_MODULE_COM = 0
    NET_SDK_INIT_CFG_ABILITY = 1
    NET_SDK_INIT_CFG_SDK_PATH = 2
    NET_SDK_INIT_CFG_LIBEAY_PATH = 3
    NET_SDK_INIT_CFG_SSLEAY_PATH = 4
    NET_SDK_INIT_CFG_PRIVATE_PATH = 5

class ALARM_LCOMMAND_ENUM(Enum):
    COMM_ALARM_ACS = 0x5002
    COMM_ID_INFO_ALARM = 0x5200
    COMM_ALARM_V30 = 0x4000
    COMM_ISAPI_ALARM = 0x6009
    COMM_UPLOAD_FACESNAP_RESULT = 0x1112
    COMM_SNAP_MATCH_ALARM = 0x2902

# ========== 添加所有必要的结构体定义 ==========
class NET_DVR_TIME(Structure):
    _fields_ = [
        ("dwYear", C_DWORD),
        ("dwMonth", C_DWORD),
        ("dwDay", C_DWORD),
        ("dwHour", C_DWORD),
        ("dwMinute", C_DWORD),
        ("dwSecond", C_DWORD)
    ]

class NET_DVR_TIME_V50(Structure):
    _fields_ = [
        ("wYear", c_ubyte),
        ("byMonth", c_ubyte),
        ("byDay", c_ubyte),
        ("byHour", c_ubyte),
        ("byMinute", c_ubyte),
        ("bySecond ", c_ubyte)
    ]

class NET_DVR_USER_LOGIN_INFO(Structure):
    _fields_ = [
        ("sDeviceAddress", c_char * 129),
        ("byUseTransport", C_BYTE),
        ("wPort", C_WORD),
        ("sUserName", c_char * 64),
        ("sPassword", c_char * 64),
        ("cbLoginResult", c_void_p),
        ("pUser", c_void_p),
        ("bUseAsynLogin", C_BYTE),
        ("byProxyType", C_BYTE),
        ("byUseUTCTime", C_BYTE),
        ("byLoginMode", C_BYTE),
        ("byHttps", C_BYTE),
        ("iProxyID", C_LONG),
        ("byVerifyMode", C_BYTE),
        ("byRes3", C_BYTE * 119)
    ]

class NET_DVR_DEVICEINFO_V30(Structure):
    _fields_ = [
        ("sSerialNumber", C_BYTE * 48),
        ("byAlarmInPortNum", C_BYTE),
        ("byAlarmOutPortNum", C_BYTE),
        ("byDiskNum", C_BYTE),
        ("byDVRType", C_BYTE),
        ("byChanNum", C_BYTE),
        ("byStartChan", C_BYTE),
        ("byAudioChanNum", C_BYTE),
        ("byIPChanNum", C_BYTE),
        ("byZeroChanNum", C_BYTE),
        ("byMainProto", C_BYTE),
        ("bySubProto", C_BYTE),
        ("bySupport", C_BYTE),
        ("bySupport1", C_BYTE),
        ("bySupport2", C_BYTE),
        ("wDevType", C_WORD),
        ("bySupport3", C_BYTE),
        ("byMultiStreamProto", C_BYTE),
        ("byStartDChan", C_BYTE),
        ("byStartDTalkChan", C_BYTE),
        ("byHighDChanNum", C_BYTE),
        ("bySupport4", C_BYTE),
        ("byLanguageType", C_BYTE),
        ("byVoiceInChanNum", C_BYTE),
        ("byStartVoiceInChanNo", C_BYTE),
        ("bySupport5", C_BYTE),
        ("bySupport6", C_BYTE),
        ("byMirrorChanNum", C_BYTE),
        ("wStartMirrorChanNo", C_WORD),
        ("bySupport7", C_BYTE),
        ("byRes2", C_BYTE),
    ]

class NET_DVR_DEVICEINFO_V40(Structure):
    _fields_ = [
        ("struDeviceV30", NET_DVR_DEVICEINFO_V30),
        ("bySupportLock", C_BYTE),
        ("byRetryLoginTime", C_BYTE),
        ("byPasswordLevel", C_BYTE),
        ("byProxyType", C_BYTE),
        ("dwSurplusLockTime", C_DWORD),
        ("byCharEncodeType", C_BYTE),
        ("bySupportDev5", C_BYTE),
        ("bySupport", C_BYTE),
        ("byLoginMode", C_BYTE),
        ("dwOEMCode", C_DWORD),
        ("iResidualValidity", C_LONG),
        ("byResidualValidity", C_BYTE),
        ("bySingleStartDTalkChan", C_BYTE),
        ("bySingleDTalkChanNums", C_BYTE),
        ("byPassWordResetLevel", C_BYTE),
        ("bySupportStreamEncrypt", C_BYTE),
        ("byMarketType", C_BYTE),
        ("byRes2", C_BYTE * 238)
    ]

class NET_DVR_STREAM_INFO(Structure):
    _fields_ = [
        ("dwChannel", C_DWORD),
        ("dwSize", C_DWORD),
        ("byID",C_BYTE),
        ("byRes", C_BYTE * 128)
    ]

class NET_DVR_VOD_PARA(Structure):
    _fields_ = [
        ("dwSize", c_uint),
        ("struIDInfo", NET_DVR_STREAM_INFO),
        ("hWnd", C_HWND),
        ("struBeginTime", NET_DVR_TIME),
        ("struEndTime", NET_DVR_TIME),
        ("byAudioFileType", C_BYTE),
        ("byStreamType", C_BYTE),
        ("byDownload", C_BYTE),
        ("byRes", C_BYTE * 125)
    ]

class NET_DVR_PLAYCOND(Structure):
    _fields_ = [
        ("dwChannel", C_DWORD),
        ("dwStreamType", C_DWORD),
        ("dwLinkMode", C_DWORD),
        ("struStartTime", NET_DVR_TIME),
        ("struStopTime", NET_DVR_TIME),
        ("byCard", C_BYTE * 32),
        ("byRes", C_BYTE * 32)
    ]

class NET_DVR_LOCAL_SDK_PATH(Structure):
    _fields_ = [
        ('sPath', c_char * 256),
        ('byRes', C_BYTE * 128),
    ]

class NET_DVR_PREVIEWINFO(Structure):
    _fields_ = [
        ('lChannel', C_LONG),
        ('dwStreamType', C_DWORD),
        ('dwLinkMode', C_DWORD),
        ('hPlayWnd', C_HWND),
        ('bBlocked', C_BOOL),
        ('bPassbackRecord', C_BOOL),
        ('byPreviewMode', C_BYTE),
        ('byStreamID', C_BYTE * 32),
        ('byProtoType', C_BYTE),
        ('byRes1', C_BYTE),
        ('byVideoCodingType', C_BYTE),
        ('dwDisplayBufNum', C_DWORD),
        ('byNPQMode', C_BYTE),
        ('byRecvMetaData', C_BYTE),
        ('byDataType', C_BYTE),
        ('byRes', C_BYTE * 213),
    ]

# ========== 添加所有必要的函数原型定义 ==========
# 加载HCNetSDK库
try:
    hcnetsdk = load_library(netsdkdllpath)
except Exception as e:
    print(f"加载HCNetSDK库失败: {e}")
    hcnetsdk = None

# 定义函数原型
if hcnetsdk:
    # 初始化函数
    hcnetsdk.NET_DVR_Init.restype = C_BOOL
    
    # 清理函数
    hcnetsdk.NET_DVR_Cleanup.restype = None
    
    # 获取错误码
    hcnetsdk.NET_DVR_GetLastError.restype = C_LONG
    
    # 登录函数
    hcnetsdk.NET_DVR_Login_V40.argtypes = [POINTER(NET_DVR_USER_LOGIN_INFO), POINTER(NET_DVR_DEVICEINFO_V40)]
    hcnetsdk.NET_DVR_Login_V40.restype = C_LONG
    
    # 登出函数
    hcnetsdk.NET_DVR_Logout.argtypes = [C_LONG]
    hcnetsdk.NET_DVR_Logout.restype = C_BOOL
    
    # 按时间回放
    hcnetsdk.NET_DVR_PlayBackByTime_V50.argtypes = [C_LONG, POINTER(NET_DVR_VOD_PARA)]
    hcnetsdk.NET_DVR_PlayBackByTime_V50.restype = C_LONG
    
    # 回放控制
    hcnetsdk.NET_DVR_PlayBackControl_V40.argtypes = [C_LONG, C_DWORD, c_void_p, C_DWORD, c_void_p, c_void_p]
    hcnetsdk.NET_DVR_PlayBackControl_V40.restype = C_BOOL
    
    # 按时间下载
    hcnetsdk.NET_DVR_GetFileByTime_V40.argtypes = [C_LONG, c_char_p, POINTER(NET_DVR_PLAYCOND)]
    hcnetsdk.NET_DVR_GetFileByTime_V40.restype = C_LONG
    
    # 获取下载进度
    hcnetsdk.NET_DVR_GetDownloadPos.argtypes = [C_LONG]
    hcnetsdk.NET_DVR_GetDownloadPos.restype = C_INT64
    
    # 停止回放
    hcnetsdk.NET_DVR_StopPlayBack.argtypes = [C_LONG]
    hcnetsdk.NET_DVR_StopPlayBack.restype = C_BOOL
    
    # 停止下载
    hcnetsdk.NET_DVR_StopGetFile.argtypes = [C_LONG]
    hcnetsdk.NET_DVR_StopGetFile.restype = C_BOOL
    
    # 设置连接时间
    hcnetsdk.NET_DVR_SetConnectTime.argtypes = [C_DWORD, C_DWORD]
    hcnetsdk.NET_DVR_SetConnectTime.restype = C_BOOL
    
    # 设置重连参数
    hcnetsdk.NET_DVR_SetReconnect.argtypes = [C_DWORD, C_BOOL]
    hcnetsdk.NET_DVR_SetReconnect.restype = C_BOOL
    
    # 设置回调函数
    hcnetsdk.NET_DVR_SetPlayDataCallBack_V40.argtypes = [C_LONG, c_void_p, c_void_p]
    hcnetsdk.NET_DVR_SetPlayDataCallBack_V40.restype = C_BOOL
    
    # 设置SDK初始化配置
    hcnetsdk.NET_DVR_SetSDKInitCfg.argtypes = [C_LONG, c_void_p]
    hcnetsdk.NET_DVR_SetSDKInitCfg.restype = C_BOOL
    
    # 设置日志
    hcnetsdk.NET_DVR_SetLogToFile.argtypes = [C_DWORD, c_char_p, C_BOOL]
    hcnetsdk.NET_DVR_SetLogToFile.restype = C_BOOL

# 定义回调函数类型
REALDATACALLBACK = fun_ctype(None, C_LONG, C_DWORD, POINTER(C_BYTE), C_DWORD, c_void_p)

# ========== 导出必要的函数和结构体 ==========
# 导出结构体
NET_DVR_TIME = NET_DVR_TIME
NET_DVR_USER_LOGIN_INFO = NET_DVR_USER_LOGIN_INFO
NET_DVR_DEVICEINFO_V40 = NET_DVR_DEVICEINFO_V40
NET_DVR_STREAM_INFO = NET_DVR_STREAM_INFO
NET_DVR_VOD_PARA = NET_DVR_VOD_PARA
NET_DVR_PLAYCOND = NET_DVR_PLAYCOND
NET_DVR_LOCAL_SDK_PATH = NET_DVR_LOCAL_SDK_PATH
NET_DVR_PREVIEWINFO = NET_DVR_PREVIEWINFO

# 导出常量
NET_DVR_PLAYSTART = NET_DVR_PLAYSTART
NET_DVR_SYSHEAD = NET_DVR_SYSHEAD
NET_DVR_STREAMDATA = NET_DVR_STREAMDATA

# 导出枚举
NET_SDK_INIT_CFG_TYPE = NET_SDK_INIT_CFG_TYPE
NET_SDK_LOCAL_CFG_TYPE = NET_SDK_LOCAL_CFG_TYPE
ALARM_LCOMMAND_ENUM = ALARM_LCOMMAND_ENUM

# 导出回调类型
REALDATACALLBACK = REALDATACALLBACK

# 导出函数（通过模块属性）
NET_DVR_Init = hcnetsdk.NET_DVR_Init if hcnetsdk else None
NET_DVR_Cleanup = hcnetsdk.NET_DVR_Cleanup if hcnetsdk else None
NET_DVR_GetLastError = hcnetsdk.NET_DVR_GetLastError if hcnetsdk else None
NET_DVR_Login_V40 = hcnetsdk.NET_DVR_Login_V40 if hcnetsdk else None
NET_DVR_Logout = hcnetsdk.NET_DVR_Logout if hcnetsdk else None
NET_DVR_PlayBackByTime_V50 = hcnetsdk.NET_DVR_PlayBackByTime_V50 if hcnetsdk else None
NET_DVR_PlayBackControl_V40 = hcnetsdk.NET_DVR_PlayBackControl_V40 if hcnetsdk else None
NET_DVR_GetFileByTime_V40 = hcnetsdk.NET_DVR_GetFileByTime_V40 if hcnetsdk else None
NET_DVR_GetDownloadPos = hcnetsdk.NET_DVR_GetDownloadPos if hcnetsdk else None
NET_DVR_StopPlayBack = hcnetsdk.NET_DVR_StopPlayBack if hcnetsdk else None
NET_DVR_StopGetFile = hcnetsdk.NET_DVR_StopGetFile if hcnetsdk else None
NET_DVR_SetConnectTime = hcnetsdk.NET_DVR_SetConnectTime if hcnetsdk else None
NET_DVR_SetReconnect = hcnetsdk.NET_DVR_SetReconnect if hcnetsdk else None
NET_DVR_SetPlayDataCallBack_V40 = hcnetsdk.NET_DVR_SetPlayDataCallBack_V40 if hcnetsdk else None
NET_DVR_SetSDKInitCfg = hcnetsdk.NET_DVR_SetSDKInitCfg if hcnetsdk else None
NET_DVR_SetLogToFile = hcnetsdk.NET_DVR_SetLogToFile if hcnetsdk else None